home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / POV-Ray 3.0.2 / src / SOURCE / BSPHERE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-02  |  12.9 KB  |  668 lines  |  [TEXT/CWIE]

  1. /*****************************************************************************
  2. *                bsphere.c
  3. *
  4. *  This module implements the bounding sphere calculations.
  5. *
  6. *  from Persistence of Vision(tm) Ray Tracer
  7. *  Copyright 1996 Persistence of Vision Team
  8. *---------------------------------------------------------------------------
  9. *  NOTICE: This source code file is provided so that users may experiment
  10. *  with enhancements to POV-Ray and to port the software to platforms other
  11. *  than those supported by the POV-Ray Team.  There are strict rules under
  12. *  which you are permitted to use this file.  The rules are in the file
  13. *  named POVLEGAL.DOC which should be distributed with this file. If
  14. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  15. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  16. *  Forum.  The latest version of POV-Ray may be found there as well.
  17. *
  18. * This program is based on the popular DKB raytracer version 2.12.
  19. * DKBTrace was originally written by David K. Buck.
  20. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  21. *
  22. *****************************************************************************/
  23.  
  24. #include "frame.h"
  25. #include "vector.h"
  26. #include "povproto.h"
  27. #include "bsphere.h"
  28.  
  29.  
  30.  
  31. /*****************************************************************************
  32. * Local preprocessor defines
  33. ******************************************************************************/
  34.  
  35. #define BRANCHING_FACTOR 4
  36.  
  37.  
  38.  
  39. /*****************************************************************************
  40. * Local typedefs
  41. ******************************************************************************/
  42.  
  43.  
  44.  
  45. /*****************************************************************************
  46. * Local variables
  47. ******************************************************************************/
  48.  
  49. static int maxelements, Axis;
  50.  
  51.  
  52.  
  53. /*****************************************************************************
  54. * Static functions
  55. ******************************************************************************/
  56.  
  57. static void merge_spheres PARAMS((VECTOR C, DBL *r, VECTOR C1, DBL r1, VECTOR C2, DBL r2));
  58. static void recompute_bound PARAMS((BSPHERE_TREE *Node));
  59.  
  60. static int find_axis PARAMS((BSPHERE_TREE **Elements, int first, int last));
  61. static void build_area_table PARAMS((BSPHERE_TREE **Elements, int a, int b, DBL *areas));
  62. static int sort_and_split PARAMS((BSPHERE_TREE **Root, BSPHERE_TREE **Elements, int *nElem, int first, int last));
  63.  
  64. static int CDECL comp_elements PARAMS((CONST void *in_a, CONST void *in_b));
  65.  
  66.  
  67.  
  68. /*****************************************************************************
  69. *
  70. * FUNCTION
  71. *
  72. *   merge_spheres
  73. *
  74. * INPUT
  75. *
  76. *   C, r           - Center and radius^2 of new sphere
  77. *   C1, r1, C2, r2 - Centers and radii^2 of spheres to merge
  78. *   
  79. * OUTPUT
  80. *
  81. *   C, r
  82. *   
  83. * RETURNS
  84. *   
  85. * AUTHOR
  86. *
  87. *   Dieter Bayer
  88. *   
  89. * DESCRIPTION
  90. *
  91. *   Calculate a sphere that encloses two given spheres.
  92. *
  93. * CHANGES
  94. *
  95. *   Jul 1994 : Creation.
  96. *
  97. *   Oct 1994 : Added test for enclosed spheres. Calculate optimal sphere. [DB]
  98. *
  99. ******************************************************************************/
  100.  
  101. static void merge_spheres(C, r, C1, r1, C2, r2)
  102. VECTOR C, C1, C2;
  103. DBL *r, r1, r2;
  104. {
  105.   DBL l, r1r, r2r, k1, k2;
  106.   VECTOR D;
  107.  
  108.   VSub(D, C1, C2);
  109.  
  110.   VLength(l, D);
  111.  
  112.   /* Check if one sphere encloses the other. */
  113.  
  114.   r1r = sqrt(r1);
  115.   r2r = sqrt(r2);
  116.  
  117.   if (l + r1r <= r2r)
  118.   {
  119.     Assign_Vector(C, C2);
  120.  
  121.     *r = r2;
  122.  
  123.     return;
  124.   }
  125.  
  126.   if (l + r2r <= r1r)
  127.   {
  128.     Assign_Vector(C, C1);
  129.  
  130.     *r = r1;
  131.  
  132.     return;
  133.   }
  134.   
  135.   k1 = (1.0 + (r1r - r2r) / l) / 2.0;
  136.   k2 = (1.0 + (r2r - r1r) / l) / 2.0;
  137.  
  138.   VLinComb2(C, k1, C1, k2, C2);
  139.  
  140.   *r = Sqr((l + r1r + r2r) / 2.0);
  141. }
  142.  
  143.  
  144.  
  145. /*****************************************************************************
  146. *
  147. * FUNCTION
  148. *
  149. *   recompute_bound
  150. *
  151. * INPUT
  152. *
  153. *   Node - Pointer to node
  154. *
  155. * OUTPUT
  156. *
  157. *   Node
  158. *
  159. * RETURNS
  160. *
  161. * AUTHOR
  162. *
  163. *   Dieter Bayer
  164. *
  165. * DESCRIPTION
  166. *
  167. *   Recompute the bounding sphere of a given node in the bounding hierarchy,
  168. *   i. e. find the bounding sphere that encloses the bounding spheres
  169. *   of all nodes.
  170. *
  171. *   NOTE: The sphere found is probably not the tightest sphere possible!
  172. *
  173. * CHANGES
  174. *
  175. *   Jul 1994 : Creation.
  176. *
  177. *   Oct 1994 : Improved bounding sphere calculation. [DB]
  178. *
  179. ******************************************************************************/
  180.  
  181. static void recompute_bound(Node)
  182. BSPHERE_TREE *Node;
  183. {
  184.   short i;
  185.   DBL r2;
  186.   VECTOR C;
  187.  
  188.   COOPERATE_1
  189.  
  190.   Assign_Vector(C, Node->Node[0]->C);
  191.  
  192.   r2 = Node->Node[0]->r2;
  193.  
  194.   for (i = 1; i < Node->Entries; i++)
  195.   {
  196.     merge_spheres(C, &r2, C, r2, Node->Node[i]->C, Node->Node[i]->r2);
  197.   }
  198.  
  199.   Assign_Vector(Node->C, C);
  200.  
  201.   Node->r2 = r2;
  202. }
  203.  
  204.  
  205.  
  206. /*****************************************************************************
  207. *
  208. * FUNCTION
  209. *
  210. *   comp_elements
  211. *
  212. * INPUT
  213. *
  214. *   in_a, in_b - elements to compare
  215. *
  216. * OUTPUT
  217. *
  218. * RETURNS
  219. *
  220. *   int - result of comparison
  221. *
  222. * AUTHOR
  223. *
  224. *   Dieter Bayer
  225. *
  226. * DESCRIPTION
  227. *
  228. *   -
  229. *
  230. * CHANGES
  231. *
  232. *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
  233. *
  234. ******************************************************************************/
  235.  
  236. static int CDECL comp_elements(in_a, in_b)
  237. CONST void *in_a;
  238. CONST void *in_b;
  239. {
  240.   DBL am, bm;
  241.  
  242.   am = (*(BSPHERE_TREE **)in_a)->C[Axis];
  243.   bm = (*(BSPHERE_TREE **)in_b)->C[Axis];
  244.  
  245.   if (am < bm - EPSILON)
  246.   {
  247.     return (-1);
  248.   }
  249.   else
  250.   {
  251.     if (am > bm + EPSILON)
  252.     {
  253.       return (1);
  254.     }
  255.     else
  256.     {
  257.       return (0);
  258.     }
  259.   }
  260. }
  261.  
  262.  
  263.  
  264. /*****************************************************************************
  265. *
  266. * FUNCTION
  267. *
  268. *   find_axis
  269. *
  270. * INPUT
  271. *
  272. * OUTPUT
  273. *
  274. * RETURNS
  275. *
  276. * AUTHOR
  277. *
  278. *   Dieter Bayer
  279. *
  280. * DESCRIPTION
  281. *
  282. *   -
  283. *
  284. * CHANGES
  285. *
  286. *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
  287. *
  288. ******************************************************************************/
  289.  
  290. static int find_axis(Elements, first, last)
  291. BSPHERE_TREE **Elements;
  292. int first, last;
  293. {
  294.   int which = X;
  295.   int i;
  296.   DBL e, d = - BOUND_HUGE;
  297.   VECTOR C, mins, maxs;
  298.  
  299.   Make_Vector(mins,  BOUND_HUGE,  BOUND_HUGE,  BOUND_HUGE);
  300.   Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
  301.  
  302.   for (i = first; i < last; i++)
  303.   {
  304.     Assign_Vector(C, Elements[i]->C);
  305.  
  306.     mins[X] = min(mins[X], C[X]);
  307.     maxs[X] = max(maxs[X], C[X]);
  308.  
  309.     mins[Y] = min(mins[Y], C[Y]);
  310.     maxs[Y] = max(maxs[Y], C[Y]);
  311.  
  312.     mins[Z] = min(mins[Z], C[Z]);
  313.     maxs[Z] = max(maxs[Z], C[Z]);
  314.   }
  315.  
  316.   e = maxs[X] - mins[X];
  317.  
  318.   if (e > d)
  319.   {
  320.     d = e;  which = X;
  321.   }
  322.  
  323.   e = maxs[Y] - mins[Y];
  324.  
  325.   if (e > d)
  326.   {
  327.     d = e;  which = Y;
  328.   }
  329.  
  330.   e = maxs[Z] - mins[Z];
  331.  
  332.   if (e > d)
  333.   {
  334.     which = Z;
  335.   }
  336.  
  337.   return (which);
  338. }
  339.  
  340.  
  341.  
  342. /*****************************************************************************
  343. *
  344. * FUNCTION
  345. *
  346. *   build_area_table
  347. *
  348. * INPUT
  349. *
  350. * OUTPUT
  351. *
  352. * RETURNS
  353. *
  354. * AUTHOR
  355. *
  356. *   Dieter Bayer
  357. *
  358. * DESCRIPTION
  359. *
  360. *   Generates a table of bounding sphere surface areas.
  361. *
  362. * CHANGES
  363. *
  364. *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
  365. *
  366. ******************************************************************************/
  367.  
  368. static void build_area_table(Elements, a, b, areas)
  369. BSPHERE_TREE **Elements;
  370. int a, b;
  371. DBL *areas;
  372. {
  373.   int i, imin, dir;
  374.   DBL r2;
  375.   VECTOR C;
  376.  
  377.   if (a < b)
  378.   {
  379.     imin = a;  dir = 1;
  380.   }
  381.   else
  382.   {
  383.     imin = b;  dir = -1;
  384.   }
  385.  
  386.   Assign_Vector(C, Elements[a]->C);
  387.  
  388.   r2 = Elements[a]->r2;
  389.  
  390.   for (i = a; i != (b + dir); i += dir)
  391.   {
  392.     merge_spheres(C, &r2, C, r2, Elements[i]->C, Elements[i]->r2);
  393.  
  394.     areas[i-imin] = r2;
  395.   }
  396. }
  397.  
  398.  
  399.  
  400. /*****************************************************************************
  401. *
  402. * FUNCTION
  403. *
  404. *   sort_and_split
  405. *
  406. * INPUT
  407. *
  408. * OUTPUT
  409. *
  410. * RETURNS
  411. *
  412. * AUTHOR
  413. *
  414. *   Dieter Bayer
  415. *
  416. * DESCRIPTION
  417. *
  418. *   -
  419. *
  420. * CHANGES
  421. *
  422. *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
  423. *
  424. ******************************************************************************/
  425.  
  426. static int sort_and_split(Root, Elements, nElem, first, last)
  427. BSPHERE_TREE **Root;
  428. BSPHERE_TREE **Elements;
  429. int *nElem, first, last;
  430. {
  431.   int size, i, best_loc;
  432.   DBL *area_left, *area_right;
  433.   DBL best_index, new_index;
  434.   BSPHERE_TREE *cd;
  435.  
  436.   Axis = find_axis(Elements, first, last);
  437.  
  438.   size = last - first;
  439.  
  440.   if (size <= 0)
  441.   {
  442.     return (1);
  443.   }
  444.  
  445.   /*
  446.    * Actually, we could do this faster in several ways. We could use a
  447.    * logn algorithm to find the median along the given axis, and then a
  448.    * linear algorithm to partition along the axis. Oh well.
  449.    */
  450.  
  451.   QSORT((void *)(&Elements[first]), (size_t)size, sizeof(BSPHERE_TREE *), comp_elements);
  452.  
  453.   /*
  454.    * area_left[] and area_right[] hold the surface areas of the bounding
  455.    * boxes to the left and right of any given point. E.g. area_left[i] holds
  456.    * the surface area of the bounding box containing Elements 0 through i and
  457.    * area_right[i] holds the surface area of the box containing Elements
  458.    * i through size-1.
  459.    */
  460.  
  461.   area_left  = (DBL *)POV_MALLOC(size * sizeof(DBL), "blob bounding hierarchy");
  462.   area_right = (DBL *)POV_MALLOC(size * sizeof(DBL), "blob bounding hierarchy");
  463.  
  464.   /* Precalculate the areas for speed. */
  465.  
  466.   build_area_table(Elements, first, last - 1, area_left);
  467.   build_area_table(Elements, last - 1, first, area_right);
  468.  
  469.   best_index = area_right[0] * (size - 3.0);
  470.  
  471.   best_loc = - 1;
  472.  
  473.   /*
  474.    * Find the most effective point to split. The best location will be
  475.    * the one that minimizes the function N1*A1 + N2*A2 where N1 and N2
  476.    * are the number of objects in the two groups and A1 and A2 are the
  477.    * surface areas of the bounding boxes of the two groups.
  478.    */
  479.  
  480.   for (i = 0; i < size - 1; i++)
  481.   {
  482.     new_index = (i + 1) * area_left[i] + (size - 1 - i) * area_right[i + 1];
  483.  
  484.     if (new_index < best_index)
  485.     {
  486.       best_index = new_index;
  487.       best_loc = i + first;
  488.     }
  489.   }
  490.  
  491.   POV_FREE(area_left);
  492.   POV_FREE(area_right);
  493.  
  494.   /*
  495.    * Stop splitting if the BRANCHING_FACTOR is reached or
  496.    * if splitting stops being effective.
  497.    */
  498.  
  499.   if ((size <= BRANCHING_FACTOR) || (best_loc < 0))
  500.   {
  501.     cd = (BSPHERE_TREE *)POV_MALLOC(sizeof(BSPHERE_TREE), "blob bounding hierarchy");
  502.  
  503.     cd->Entries = (short)size;
  504.  
  505.     cd->Node = (BSPHERE_TREE **)POV_MALLOC(size*sizeof(BSPHERE_TREE *), "blob bounding hierarchy");
  506.  
  507.     for (i = 0; i < size; i++)
  508.     {
  509.       cd->Node[i] = Elements[first+i];
  510.     }
  511.  
  512.     recompute_bound(cd);
  513.  
  514.     *Root = cd;
  515.  
  516.     if (*nElem > maxelements)
  517.     {
  518.       /* Prim array overrun, increase array by 50%. */
  519.  
  520.       maxelements = 1.5 * maxelements;
  521.  
  522.       /* For debugging only. */
  523.  
  524.       Debug_Info("Reallocing elements to %d\n", maxelements);
  525.  
  526.       Elements = (BSPHERE_TREE **)POV_REALLOC(Elements, maxelements * sizeof(BSPHERE_TREE *), "bounding slabs");
  527.     }
  528.  
  529.     Elements[*nElem] = cd;
  530.  
  531.     (*nElem)++;
  532.  
  533.     return (1);
  534.   }
  535.   else
  536.   {
  537.     sort_and_split(Root, Elements, nElem, first, best_loc + 1);
  538.  
  539.     sort_and_split(Root, Elements, nElem, best_loc + 1, last);
  540.  
  541.     return (0);
  542.   }
  543. }
  544.  
  545.  
  546.  
  547. /*****************************************************************************
  548. *
  549. * FUNCTION
  550. *
  551. *   Build_Bounding_Sphere_Hierarchy
  552. *
  553. * INPUT
  554. *
  555. *   nElem    - number of elements in Elements
  556. *   Elements - array containing nElem elements
  557. *
  558. * OUTPUT
  559. *
  560. *   Root     - root node of the hierarchy
  561. *
  562. * RETURNS
  563. *
  564. * AUTHOR
  565. *
  566. *   Dieter Bayer
  567. *
  568. * DESCRIPTION
  569. *
  570. *   Create the bounding sphere hierarchy for a given set of elements.
  571. *   One element consists of an element number (index into the array
  572. *   of elements; e.g. blob components, triangles) and a bounding
  573. *   sphere enclosing this element (center and squared radius).
  574. *
  575. * CHANGES
  576. *
  577. *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
  578. *
  579. ******************************************************************************/
  580.  
  581. void Build_Bounding_Sphere_Hierarchy(Root, nElem, Elements)
  582. int nElem;
  583. BSPHERE_TREE **Root, **Elements;
  584. {
  585.   int low, high;
  586.  
  587.   /*
  588.    * This is a resonable guess at the number of elements needed.
  589.    * This array will be reallocated as needed if it isn't.
  590.    */
  591.  
  592.   maxelements = 2 * nElem;
  593.  
  594.   /*
  595.    * Do a sort on the elements, with the end result being
  596.    * a tree of objects sorted along the x, y, and z axes.
  597.    */
  598.  
  599.   if (nElem > 0)
  600.   {
  601.     low  = 0;
  602.     high = nElem;
  603.  
  604.     while (sort_and_split(Root, Elements, &nElem, low, high) == 0)
  605.     {
  606.       low  = high;
  607.       high = nElem;
  608.     }
  609.   }
  610. }
  611.  
  612.  
  613.  
  614. /*****************************************************************************
  615. *
  616. * FUNCTION
  617. *
  618. *   Destroy_Bounding_Sphere_Hierarchy
  619. *
  620. * INPUT
  621. *
  622. *   Node - Pointer to current node
  623. *
  624. * OUTPUT
  625. *
  626. *   Node
  627. *
  628. * RETURNS
  629. *
  630. * AUTHOR
  631. *
  632. *   Dieter Bayer
  633. *
  634. * DESCRIPTION
  635. *
  636. *   Destroy bounding sphere hierarchy.
  637. *
  638. * CHANGES
  639. *
  640. *   Aug 1994 : Creation.
  641. *
  642. *   Dec 1994 : Fixed memory leakage. [DB]
  643. *
  644. ******************************************************************************/
  645.  
  646. void Destroy_Bounding_Sphere_Hierarchy(Node)
  647. BSPHERE_TREE *Node;
  648. {
  649.   short i;
  650.  
  651.   if (Node != NULL)
  652.   {
  653.     if (Node->Entries > 0)
  654.     {
  655.       /* This is a node. Free sub-nodes. */
  656.  
  657.       for (i = 0; i < Node->Entries; i++)
  658.       {
  659.         Destroy_Bounding_Sphere_Hierarchy(Node->Node[i]);
  660.       }
  661.  
  662.       POV_FREE(Node->Node);
  663.     }
  664.  
  665.     POV_FREE(Node);
  666.   }
  667. }
  668.